home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Demos / Evatac Software / Preditor 3.0 / Tools / Language Module Builder / Sources / HtmlParse.c < prev    next >
Text File  |  1996-02-04  |  15KB  |  758 lines

  1. /************************************************************
  2.  
  3.     HtmlParse.c
  4.     C Source to Preditor 3
  5.  
  6.     Language Module Code for the "HTML" language
  7.  
  8.     © Copyright Evatac Software  1988-1996
  9.     All rights reserved
  10.  
  11. ************************************************************/
  12.  
  13. #include "HtmlParse.h"
  14. #include <SetupA4.h>
  15. #include <MixedMode.h>
  16. #include <Ctype.h>
  17.  
  18. #ifndef THINKC
  19. #include <A4Stuff.h>
  20. #else
  21. #define SetCurrentA4()    0; RememberA4()
  22. #define SetA4(x)        SetUpA4()
  23. #endif
  24.  
  25. #ifdef powerc
  26. ProcInfoType __procinfo = LanguageUPPInfo;
  27. #endif
  28.  
  29. // Remove the comment on the following line to include hrefs in reference popup
  30. // #define INCLUDE_HREFS        1
  31.  
  32. static languageGlobals            globals;
  33. static ExternalCallbackBlock    *callbacks;
  34. static Boolean                    inMarkup, inNegation, inHeader = false;
  35.  
  36. /*
  37.  * * * *     HTML LANGUAGE INDENT HANDLER       * * * * * *
  38.  */
  39.  
  40. static long _languageConvertToTabs(
  41.     Char    *text,
  42.     long     length,
  43.     long    hardTab
  44.     )
  45. {
  46.     int        tabs   = length / hardTab;
  47.     int        spaces = length % hardTab;
  48.     int        newLen = tabs + spaces;
  49.  
  50.     while (tabs-- > 0)
  51.         *(text++) = 9;
  52.     while (spaces-- > 0)
  53.         *(text++) = ' ';
  54.  
  55.     return(newLen);
  56. }
  57.  
  58. /*
  59.  * _languageHandleIndent
  60.  *
  61.  * Indent the selected lines according to the buffer indentation settings
  62.  */
  63. static void _languageHandleIndent(
  64.     void        *extData
  65.     )
  66. {
  67.     long        anchor, end, pos, length;
  68.     long        lineStart;
  69.     long        i, x, newPos = -1;
  70.     long        lineNumber, endLineNumber, leading;
  71.     short        spacesPerTab, hardTab;
  72.     Char        text[256];
  73.     
  74.     extGetSelection(callbacks, &anchor, &end);
  75.  
  76.     if (anchor > end) {
  77.         pos = anchor; anchor = end; end = pos;   /* Swap */
  78.     }
  79.     
  80.     lineNumber    = extLineFromPosition(callbacks, anchor);
  81.     endLineNumber = extLineFromPosition(callbacks, end);
  82.  
  83.     /*
  84.      * Indent each line in the selection
  85.      */
  86.      
  87.     while (lineNumber <= endLineNumber) {
  88.         
  89.         if (lineNumber <= 1) {
  90.             lineNumber++;
  91.             continue;
  92.         }
  93.         
  94.         leading  = extGetLeading(callbacks, lineNumber, &length,
  95.                                    &spacesPerTab, &hardTab);
  96.     
  97.         lineStart = extLineToPosition(callbacks, lineNumber);
  98.         
  99.         /*
  100.          * Select the leading spaces/tabs
  101.          */
  102.          
  103.         extSetSelection(callbacks, lineStart, lineStart + length);
  104.  
  105.         /*
  106.          * Scan back previous lines for a line that we can relate to
  107.          */
  108.  
  109.         x = 1;
  110.  
  111.         for (;;) {
  112.  
  113.             if (lineNumber - x < 1)
  114.                 break;
  115.  
  116.             leading  = extGetLeading(callbacks, lineNumber - x, &length,
  117.                                        &spacesPerTab, &hardTab);
  118.                                        
  119.             end      = extLineEnd(callbacks, lineNumber - x);
  120.             pos         = extLineToPosition(callbacks, lineNumber - x);
  121.             
  122.             /* Skip Blank lines */
  123.  
  124.             if (length == (end - pos)) {
  125.                 x++;
  126.                 continue;
  127.                }
  128.             
  129.             i = pos + length;
  130.             
  131.             /*
  132.              * Perform Indention Smarts (Still under development)
  133.              */
  134.             
  135.             extScanContents(callbacks, i);
  136.             
  137.         /*    while (i++ < end && extNextScanCharacter(callbacks, &ch)) {
  138.                 
  139.                 if (ch == '{') {
  140.                     leading += spacesPerTab;
  141.                     break;
  142.                 }
  143.             } */
  144.             
  145.             extDoneScan(callbacks);
  146.  
  147.         
  148.             /*
  149.               * Indent the line
  150.              */
  151.             
  152.             i = _languageConvertToTabs(text, leading, hardTab); 
  153.         
  154.             extInsert(callbacks, text, i);
  155.             
  156.             if (newPos == -1)
  157.                 newPos = lineStart + i;
  158.             break;
  159.         }
  160.         
  161.         lineNumber++;
  162.     }
  163.  
  164.     if (newPos >= 0)
  165.         extSetSelection(callbacks, newPos, newPos);
  166. }
  167.  
  168. /*
  169.  * * * *     C LANGUAGE PARSER       * * * * * *
  170.  */
  171.  
  172. /*
  173.  * _languageBuildString
  174.  *
  175.  * Build up a literal string or literal contant "foo" or 'foo'
  176.  */
  177. static void _languageBuildString(
  178.     languageToken            *token,
  179.     int                        c
  180.     )
  181. {
  182.     Int32    index = 1, size = kTokenStringSize;
  183.     int        origC = c;
  184.     
  185.     token->string[1]     = c;
  186.     token->type = (c == '\"' ? kSymbolStringLiteral : kSymbolCharConstant);
  187.     
  188.     if (c == 'l' || c == 'L') {
  189.         
  190.         c = languageGetChar(&globals, callbacks);
  191.         token->string[0] = c;
  192.         index = 2;
  193.     }
  194.     
  195.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  196.         
  197.         if (index < size)
  198.             token->string[++index] = c;
  199.         
  200.         if (c == origC)
  201.             break;
  202.         
  203.         else if (c == '\\') {
  204.         
  205.             c = languageGetChar(&globals, callbacks);
  206.             
  207.             if (c != -1) {
  208.                 
  209.                 if (index < size)
  210.                     token->string[++index] = c;
  211.             }
  212.         }
  213.     }
  214.     
  215.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  216.     token->string[++index] = 0;
  217. }
  218.  
  219. /*
  220.  * _languageBuildWhiteSpace
  221.  *
  222.  * Build up a directive (i.e. #define, etc)
  223.  */
  224. static void _languageBuildWhiteSpace(
  225.     languageToken             *token,
  226.     int                     c
  227.     )
  228. {
  229.     token->type = kSymbolWhiteSpace;
  230.  
  231.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  232.         
  233.         if (c != ' ' && c != '\t' && c != '\v' && c != '\n' &&
  234.             c != '\r' && c != '\f' && c != '\b') {
  235.     //    if (!isspace(c)) {
  236.             languageUngetChar(&globals, c);
  237.               return;
  238.         }
  239.     }
  240. }
  241.  
  242. /*
  243.  * _languageBuildContent
  244.  *
  245.  * 
  246.  */
  247. static void _languageBuildContent(
  248.     languageToken             *token,
  249.     int                     c
  250.     )
  251. {
  252.     Int32    index = 0, size = kTokenStringSize;
  253.     int        origC = c;
  254.     
  255.     token->type             = kSymbolContent;
  256.     token->string[++index]  = c;
  257.     
  258.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  259.         
  260.         if (c == '<') {
  261.             languageUngetChar(&globals, c);
  262.             break;
  263.         }
  264.             
  265.         if (index < size)
  266.             token->string[++index] = c;
  267.     }
  268.     
  269.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  270.     token->string[++index] = 0;
  271.     
  272.     token->endLocation     = globals.position;
  273. }
  274.  
  275. /*
  276.  * _languageBuildComment
  277.  *
  278.  */
  279. static void _languageBuildComment(
  280.     languageToken             *token,
  281.     int                     c
  282.     )
  283. {
  284.     Boolean     wasDash;
  285.  
  286.     token->type                 = kSymbolComment;
  287.     globals.startLastComment     = globals.position;
  288.  
  289.     c = languageGetChar(&globals, callbacks);
  290.     
  291.     if (c =='-') {
  292.     
  293.         wasDash = false;
  294.  
  295.         while ((c = languageGetChar(&globals, callbacks)) != -1) {
  296.  
  297.             if (c == '-')
  298.                 wasDash = true;
  299.             else if (c != '/' || !wasDash)
  300.                 wasDash = false;
  301.              else
  302.                 break;
  303.         }
  304.     }
  305. }
  306.  
  307. /*
  308.  * _languageBuildNumber
  309.  *
  310.  */
  311. static void _languageBuildNumber(
  312.     languageToken             *token,
  313.     int                     c
  314.     )
  315. {
  316.     token->type = kSymbolIntConstant;
  317.  
  318.     if (c == '0') {
  319.     
  320.         c = languageGetChar(&globals, callbacks);
  321.  
  322.         if (c == 'x' || c == 'X') {
  323.         
  324.             while ((c = languageGetChar(&globals, callbacks)) != -1) {
  325.  
  326.                 if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
  327.                     ;
  328.                 else
  329.                     break;
  330.             }
  331.         }
  332.    
  333.         else {
  334.         
  335.             while (c != -1) {
  336.     
  337.                 if (c >= '0' && c <= '7')
  338.                     ;
  339.                 else
  340.                     break;
  341.         
  342.                 c = languageGetChar(&globals, callbacks);
  343.             }
  344.         }
  345.     }
  346.     
  347.     else {                                    /* decimal */
  348.  
  349.         while ((c = languageGetChar(&globals, callbacks)) != -1) {
  350.  
  351.             if (c >= '0' && c <= '9') 
  352.                 ;
  353.             else
  354.                 break;
  355.         }
  356.  
  357.         if (c == '.') {
  358.             
  359.             token->type = kSymbolFloatConstant;
  360.  
  361.             while ((c = languageGetChar(&globals, callbacks)) != -1) {
  362.             
  363.                 if (c >= '0' && c <= '9')
  364.                     ;
  365.                  else
  366.                     break;
  367.             }
  368.         }
  369.  
  370.         if (c == 'e' || c == 'E') {
  371.         
  372.             token->type = kSymbolFloatConstant;
  373.  
  374.             c = languageGetChar(&globals, callbacks);
  375.  
  376.             if (c == '-' || c == '+')
  377.                 c = languageGetChar(&globals, callbacks);
  378.  
  379.             while (c != -1) {
  380.  
  381.                 if (c >= '0' && c <= '9')
  382.                     ;
  383.                 else
  384.                     break;
  385.  
  386.                 c = languageGetChar(&globals, callbacks);
  387.             }
  388.         }
  389.     }
  390.  
  391.     while (c != -1) {
  392.         
  393.         if (c == 'l' || c == 'L' || c == 'u' || c == 'U' ||
  394.             c == 'f' || c == 'F' || c == 'h' || c == 'H')    
  395.             ;
  396.         else
  397.             break;
  398.         
  399.         c = languageGetChar(&globals, callbacks);
  400.     }
  401.     
  402.     if (c != -1)
  403.         languageUngetChar(&globals, c);
  404. }
  405.  
  406. /*
  407.  * _languageBuildWord
  408.  *
  409.  *
  410.  */
  411. static void _languageBuildWord(
  412.     languageToken             *token,
  413.     int                     c
  414.     )
  415. {
  416.     Int32            index = 1, size = kTokenStringSize;
  417.     Char            *scan, *target;
  418.     Char            lowerStr[kTokenStringSize + 2];
  419.     
  420.     token->type = kSymbolIdentifier;
  421.  
  422.     token->string[1] = c;
  423.     
  424.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  425.  
  426.         if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'
  427.             || c >= '0' && c <= '9') {
  428.         
  429.             if (index < size)
  430.                 token->string[++index] = c;
  431.             else
  432.                 token->string[index] = '…';
  433.         }
  434.         else {
  435.         
  436.             languageUngetChar(&globals, c);
  437.             break;
  438.         }
  439.     }
  440.  
  441.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  442.     token->string[++index] = 0;
  443.     
  444.     /*
  445.      * lower case the string for lookup
  446.      */
  447.      
  448.     scan   = token->string;
  449.     target = lowerStr;
  450.     
  451.     while (*scan != 0) {
  452.         *(target++) = tolower(*scan);
  453.         scan++;
  454.     }
  455.     *target = 0;
  456.     
  457.     if (!inMarkup)
  458.         return;
  459.         
  460.     /*
  461.      * Since hashing into a large reserved word table takes time, the reserved
  462.      * word table is not loaded for "function" scanning.  We do our own
  463.      * limited keyword check
  464.      */
  465.     
  466.     if (!languageHasTable(&globals)) {
  467.         
  468.         scan = lowerStr + 1;
  469.         
  470.         if (languageCStringCompare(scan, (Char *) "href") == 0)
  471.             token->type = kSymbolReservedWord;
  472.         else if ((*scan == 'h' || *scan == 'H') &&
  473.                  (scan[1] >= '0' && scan[1] <= '5'))
  474.             token->type = kSymbolReservedWord;
  475.         
  476.         return;
  477.     }
  478.     
  479.     else if (languageTableLookup((&globals), lowerStr + 1))
  480.         token->type = kSymbolReservedWord;
  481.     else if (languageCustomTableLookup((&globals), lowerStr + 1))
  482.         token->type = kSymbolCustomWord;
  483. }
  484.  
  485. /*
  486.  * _languageGetNextToken
  487.  */
  488. static languageToken *_languageGetNextToken(void)
  489. {
  490.     int                     first, second;
  491.     Int16                    previousType;
  492.     languageToken            *token = &globals.token;
  493.    
  494.     previousType            = token->type;
  495.     token->startLocation     = globals.position;
  496.     token->majorType        = -1;
  497.  
  498.     if ((first = languageGetChar(&globals, callbacks)) == -1)
  499.         return(nil);
  500.  
  501.     token->type             = first;
  502.  
  503.     second = languagePeekChar(&globals, callbacks);
  504.     
  505.     if (!inMarkup && first != '<') {
  506.         
  507.         _languageBuildContent(token, first);
  508.     
  509.         return(token);
  510.     }
  511.     
  512.     switch(first) {
  513.  
  514. /* "strings" */
  515. /* 'character constants' */
  516.  
  517.     case '\"':
  518.     case '\'':
  519.         if (inMarkup)
  520.             _languageBuildString(token, first);
  521.         break;
  522.  
  523. /* white space */
  524.  
  525.     case ' ': case '\t': case '\v': case '\n': case '\r': case '\f': case '\b':
  526.         _languageBuildWhiteSpace(token, first);
  527.         break;
  528.  
  529. /* Markup langauge */
  530.  
  531.     case '<':
  532.         if (second == '-') {        /* Comment */
  533.             _languageBuildComment(token, first);
  534.          }
  535.         else {
  536.             inMarkup = true;
  537.             inNegation = second == '/';
  538.         }
  539.         break;
  540.     
  541.     case '>':
  542.         inMarkup   = false;
  543.         inNegation = false;
  544.         globals.startLastComment = -1;
  545.         break;
  546.         
  547. /* monographs */
  548.     case ';':
  549.     case '(':
  550.     case '#':
  551.     case ')':
  552.     case '[':
  553.     case ']':
  554.     case '}':
  555.     case '{':
  556.     case '~':
  557.     case '*':
  558.     case '%':
  559.     case '\\':
  560.     case ',':
  561.     case '?':
  562.     case '/':
  563.       break;
  564.  
  565. /* = */
  566.  
  567.     case '=':
  568.         break;
  569.  
  570. /* the rest */
  571.  
  572.     default:
  573.         if (first >= '0' && first <= '9')
  574.             _languageBuildNumber(token, first);
  575.         else if (first >= 'a' && first <= 'z' || first >= 'A' && first <= 'Z' ||
  576.                  first == '_')
  577.                _languageBuildWord(token, first);
  578.  
  579.         /* Something weird, let the parser decide. */
  580.  
  581.         break;
  582.     }
  583.  
  584.     token->endLocation    = globals.position;
  585.     
  586.     return(token);
  587. }
  588.  
  589. void languageMain(
  590.     ExternalCallbackBlock    *extCallbacks,
  591.     WindowRef                window,
  592.     long                    options,
  593.     void                    *extData
  594.     );
  595.     
  596. /*
  597.  * languageMain
  598.  *
  599.  * This is the main entrypoint to the CODE module of a language module.
  600.  * The following operations are defined:
  601.  *
  602.  *     kLanguageParse        Parse the source file, returning positions of all tokens
  603.  *                        in the file.
  604.  *  kLanguageFunctions    Parse the source file, returning the position of just the
  605.  *                        functions in the source file
  606.  *  kLanguageIncludes    Parse the source file, returning the #include files
  607.  *  kLanguageTemplate    Expand macro -- insert template
  608.  *  kLanguageIndentLine
  609.  *    kLanguageElectric    Handle electric characters (i.e. }, {, ; )
  610.  */
  611.  
  612. void main(
  613.     ExternalCallbackBlock    *extCallbacks,
  614.     WindowRef                window,
  615.     long                    options,
  616.     void                    *extData
  617.     )
  618. {
  619.     languageToken        *token;
  620.     Int16                type;
  621.     Char                *ptr;
  622.     long                 saved_a4;
  623.  
  624.     saved_a4                  = SetCurrentA4();
  625.     inMarkup                  = false;
  626.     globals.startLastComment = -1;
  627.     
  628.     languageInit(&globals, extCallbacks, options);
  629.  
  630.     callbacks    = extCallbacks;
  631.  
  632.     if (options == kLanguageTemplate) {
  633.  
  634.         languageDefaultHandler(&globals, callbacks, options, extData);
  635.     } 
  636.     
  637.     else if (options == kLanguageIndent) {
  638.         
  639.         _languageHandleIndent(extData);
  640.     }
  641.     
  642.     else if (options <= kLanguageIncludes) {
  643.         
  644.         /*
  645.          * Now parse the file, returning a series of valid return token types:
  646.          *
  647.          *        kReference
  648.          *         kKeyword
  649.          *         kComment
  650.          *        kCustomKeyword
  651.          *        kHeader
  652.          */
  653.             
  654.         while ((token = _languageGetNextToken()) != nil) {
  655.     
  656.             type = token->type;
  657.             
  658.             if (type == kSymbolReservedWord) {
  659.             
  660.                 token->majorType = kKeyword;
  661.                 ptr                 = token->string;
  662.                 
  663.                 if ((ptr[1] == 'h' && ptr[2] == 'r' && ptr[0] == 4 ||
  664.                      ptr[1] == 'H' && ptr[2] == 'R' && ptr[0] == 4) &&
  665.                      options == kLanguageParse && inMarkup) {
  666.            
  667.                     _languageBuildWhiteSpace(token, 0);
  668.                     
  669.                     /* Now get the equal sign */
  670.                     
  671.                     if ((token = _languageGetNextToken()) != nil &&
  672.                         token->type == kSymbolEqual) {
  673.                         
  674.                         _languageBuildWhiteSpace(token, 0);
  675.  
  676.                         if ((token = _languageGetNextToken()) != nil &&
  677.                             token->type == kSymbolStringLiteral) {
  678.  
  679.                             token->majorType       = kReference;    
  680.                             token->commentLocation = globals.startLastComment;
  681.                             
  682.                             extTokenReturn(callbacks, token);
  683.                             continue;
  684.                         }
  685.                     }
  686.                 }
  687.                 
  688.                 if (options == kLanguageParse)
  689.                     extTokenReturn(callbacks, token);
  690.                     
  691.                 if (inMarkup &&
  692.                     (ptr[1] == 'h' || ptr[2] == 'H') &&
  693.                      ptr[2] >= '0' && ptr[2] <= '9' && ptr[0] == 2 &&
  694.                      options != kLanguageIncludes) {
  695.            
  696.                        inHeader = !inNegation;
  697.                     
  698.                 }
  699.                 
  700.                 continue;
  701.             }
  702.         
  703.             else if (type == kSymbolCustomWord) {
  704.                 token->majorType = kCustomKeyword;
  705.             }
  706.  
  707.             else if (type == kSymbolComment)
  708.                 token->majorType = kComment;
  709.  
  710.             else if (type == kSymbolContent) {
  711.                 
  712.                 token->majorType = (inHeader ? kHeader : kContent);
  713.                 
  714.                 if (options != kLanguageParse && inHeader) {
  715.                     
  716.                     int        len = token->string[0];
  717.                     Char    *ptr = token->string + 1;
  718.                     
  719.                     /* Make sure there is something in the header */
  720.                     
  721.                     while (len-- > 0) {
  722.                         
  723.                         Char c = *(ptr++);
  724.             
  725.                         if (c != ' ' && c != '\t' && c != '\v' && c != '\n' &&
  726.                             c != '\r' && c != '\f' && c != '\b' ) {
  727.                                 
  728.                             token->commentLocation = globals.startLastComment;
  729.                             extTokenReturn(callbacks, token);
  730.                             break;
  731.                         }
  732.                     }
  733.                     
  734.                     
  735.                     continue;                    
  736.                 }
  737.             }
  738.             
  739.             /*
  740.              * Only return a token if it's a interesting token, and
  741.              * if we are doing a full parse
  742.              */
  743.              
  744.             if (token != nil &&
  745.                 token->majorType >= 0 && options == kLanguageParse)
  746.                 extTokenReturn(callbacks, token);
  747.         }
  748.     }
  749.     
  750.     /*
  751.      * Clean up after ourselves
  752.      */
  753.  
  754.     languageDone(&globals, callbacks);
  755.     
  756.     SetA4(saved_a4);
  757. }
  758.